/*
 * This is the model class
 */
package model;

import java.net.InetAddress;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Observable;
import java.util.TreeMap;
import javax.swing.DefaultListModel;

/**
 * ChatModel is the class that stores the data : Username, Netname, IP,
 * broadcastIP, userList and userPresent, sent file proposals...
 *
 * @author gb
 */
public class ChatModel extends Observable implements ChatModelCtrlr2Model {

    static boolean chatModelVerbose = true;

    private String username = "Tour";
    private String netUsername;
    private InetAddress broadcastIp;
    private DefaultListModel userList;
    private ChatMsgs chatmsgs;
    private HashMap<String, Boolean> userPresent;
    private TreeMap<SentFileProposal, Path> sentFileProposals;

    /**
     * Creates a chat model. The ChatMsgs and the DefaultListModel objects are
     * observed by the gui this is why they need to get it from outside
     *
     * @param userList the userList in which we will add the new remote users
     * @param chatmsgs the object that is going to update the GUI when it has a
     * new message
     */
    public ChatModel(DefaultListModel userList, ChatMsgs chatmsgs) {
        this.userList = userList;
        this.chatmsgs = chatmsgs;
        this.userPresent = new HashMap<String, Boolean>();
        this.sentFileProposals = new TreeMap<SentFileProposal, Path>();
    }

    static void printDebug(String callingClass, String callingFunction, String actionPerformed) {
        if (ChatModel.chatModelVerbose) {
            System.out.println("In " + callingClass + " -> " + callingFunction);
            System.out.println("\t" + actionPerformed);
        }
    }

    @Override
    public void setUsername(String username) {
        this.username = username;
    }

    @Override
    public String getUsername() {
        return this.username;
    }

    @Override
    public void setNetUsername(String netUsername) {
        this.netUsername = netUsername;
    }

    @Override
    public String getNetUsername() {
        return netUsername;
    }

    @Override
    public void setBroadcastIpAddress(InetAddress broadcastIp) {
        this.broadcastIp = broadcastIp;
    }

    @Override
    public InetAddress getBroadcastIpAddress() {
        return this.broadcastIp;
    }

    @Override
    public boolean addUserToList(String netRemoteUsername) {
        if (userPresent.get(netRemoteUsername) != null) {
            printDebug(this.getClass().getCanonicalName(), "addUserToList", "User " + netRemoteUsername + " already in the list.");
            return false;
        } else {
            printDebug(this.getClass().getCanonicalName(), "addUserToList", "Adding " + netRemoteUsername + " to list.");
            userPresent.put(netRemoteUsername, Boolean.TRUE);
            userList.addElement(netRemoteUsername);
            return true;
        }
    }

    @Override
    public boolean delUserFromList(String netRemoteUsername) {
        if (userPresent.get(netRemoteUsername) == null) {
            printDebug(this.getClass().getCanonicalName(), "delUserFromList", "User " + netRemoteUsername + " doesn't exist in the list.");
            return false;
        } else if (!userPresent.get(netRemoteUsername)) {
            printDebug(this.getClass().getCanonicalName(), "delUserFromList", "User " + netRemoteUsername + " is not in the list.");
            return false;
        } else {
            printDebug(this.getClass().getCanonicalName(), "delUserFromList", "Deleting " + netRemoteUsername + " from the list.");
            userPresent.remove(netRemoteUsername);
            userList.removeElement(netRemoteUsername);
            return true;
        }
    }

    @Override
    public void addReceivedTextMessage(String message, String from, ArrayList<String> to) {
        printDebug(this.getClass().getCanonicalName(), "addReceivedTextMessage", "Adding a message to the chat : " + message + " from " + from);
        chatmsgs.addReceivedTextMessage(message, from, this.netUsername, to);
    }

    @Override
    public void addSentTextMessage(String message, ArrayList<String> to) {
        printDebug(this.getClass().getCanonicalName(), "addReceivedTextMessage", "Adding a message to the chat : " + message + " from " + netUsername);
        chatmsgs.addSentTextMessage(message, netUsername, to);
    }

    @Override
    public void addTextNotifyFileReceived(String filename, String from, ArrayList<String> to, boolean boolReceived) {
        chatmsgs.addTextNotifyFileReception(filename, from, this.netUsername, to, boolReceived);
    }

    @Override
    public void addTextNotifyFileTransmitted(String filename, String remoteUsername, boolean boolTransmitted) {
        chatmsgs.addTextNotifyFileTransmition(filename, this.netUsername, remoteUsername, boolTransmitted);
    }

    @Override
    public void rememberFileProposal(String fileName, Path filePath, String curRmUser) {
        SentFileProposal sfp = new SentFileProposal(fileName, curRmUser);
        printDebug(this.getClass().getCanonicalName(), "rememberFileProposal", "creating a new sent file proposal linking " + sfp + " to the file " + filePath);
        this.sentFileProposals.put(sfp, filePath);
    }

    @Override
    public void forgetFileProposal(String fileName, String remoteNetname) {
        SentFileProposal sfp = new SentFileProposal(fileName, remoteNetname);
        printDebug(this.getClass().getCanonicalName(), "forgetFileProposal", "removing the proposal " + sfp + " from the map");
        this.sentFileProposals.remove(sfp);
    }

    @Override
    public Path getFilePathForProposal(String fileName, String remoteNetname) {
        SentFileProposal sfp = new SentFileProposal(fileName, remoteNetname);
        printDebug(this.getClass().getCanonicalName(), "getFilePathForProposal", "returning filePath linked to " + sfp);
        return this.sentFileProposals.get(sfp);
    }

    @Override
    public void emptyConnectedUsersList() {
        this.userPresent = new HashMap<>();
        this.userList.removeAllElements();
    }
}
